package com.taxshare.purchaser.service;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.taxshare.purchaser.constant.CodeConstant;
import com.taxshare.purchaser.entity.ElectronicledgerEntity;
import com.taxshare.purchaser.entity.PeriodEntity;
import com.taxshare.purchaser.mapper.ElectronicledgerMapper;
import com.taxshare.purchaser.mapper.PeriodMapper;
import com.taxshare.purchaser.remote.ApiClientService;
import com.taxshare.purchaser.view.dto.InvoiceAuthBodyDTO;
import com.taxshare.purchaser.view.dto.InvoiceAuthRespDTO;
import com.taxshare.response.beans.Response;
import com.taxshare.tools.util.UUIDUitl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.aspectj.apache.bcel.classfile.Code;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @ClassName: AsyncAuthService
 * @Description:
 * @author: luozhongyi
 * @date: 2021/4/9 11:33
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
@Slf4j
public class AsyncAuthService extends ServiceImpl<ElectronicledgerMapper, ElectronicledgerEntity> {

    @Autowired
    ApiClientService apiClientService;

    @Autowired
    PeriodMapper periodMapper;

    @Async
    public void auth(InvoiceAuthBodyDTO auth) {
        String period = "";
        try {
            //查询属期
            PeriodEntity periodVo = getTaxNoPeriod(auth.getNsrsbh());
            if (null != periodVo) {
                period = periodVo.getPeriod();
            } else {
                Response response = apiClientService.period(auth.getNsrsbh());
                if (CodeConstant.T0000.equals(response.getCode())) {
                    Map<String, String> resMap = JSON.parseObject(response.getData().toString(), Map.class);
                    period = resMap.get("skssq");
                    //属期更新
                    updatePeriodByTaxNo(auth.getNsrsbh(), response);
                }
            }
            auth.setPeriod(period);
            //调用北京接口
            splitAuth(auth);
        } catch (Exception e) {
            log.error("发票认证异常", e);
            updateAuthBatchError(auth, "36", "发票认证内部异常");
        }
    }

    /**
     * @param taxNo
     * @param period
     * @param operationDateEnd
     */
    @Async
    public void saveTaxPeriod(String taxNo, String period, String operationDateEnd) {
        //存在修改部分信息
        QueryWrapper<PeriodEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tax_number", taxNo);
        PeriodEntity periodEntity = periodMapper.selectOne(queryWrapper);
        //属期信息已经存在
        if (periodEntity != null) {
            updatePeriodById(periodEntity, period, operationDateEnd);
        } else {
            initPeriod(taxNo, period, operationDateEnd);
        }
    }

    /**
     * @param periodEntity
     * @param period
     * @param operationDateEnd
     */
    private void updatePeriodById(PeriodEntity periodEntity, String period, String operationDateEnd) {
        //如果当前属期和数据库属期不一致则直接刷新数据
        if (!period.equals(periodEntity.getPeriod())) {
            refreshPeriod(periodEntity.getTaxNumber(), period, operationDateEnd);
        }

    }

    /**
     * @param taxNo
     * @param response
     */
    public void updatePeriodByTaxNo(String taxNo, Response response) {
        Map<String, String> map = JSONUtil.toBean(response.getData().toString(), Map.class);
        saveTaxPeriod(taxNo,map.get("skssq"),map.get("gxczjzrq"));
    }

    /**
     * @param taxNo
     * @param period
     * @param operationDateEnd
     */
    private void initPeriod(String taxNo, String period, String operationDateEnd) {
        PeriodEntity periodEntity = new PeriodEntity();
        periodEntity.setUuid(UUIDUitl.UUID32(false));
        periodEntity.setTaxNumber(taxNo);
        periodEntity.setPeriod(period);
        periodEntity.setOperationDateEnd(operationDateEnd);
        periodEntity.setState("0");
        periodMapper.insert(periodEntity);
    }

    /**
     * 刷新属期信息
     * @param taxNo
     * @param period
     * @param operationDateEnd
     */
    private void refreshPeriod(String taxNo, String period, String operationDateEnd) {
        PeriodEntity periodEntity = new PeriodEntity();
        periodEntity.setPeriod(period);
        periodEntity.setOperationDateEnd(operationDateEnd);
        periodEntity.setState("0");
        periodEntity.setTaskno("");
        periodEntity.setApplyTaskState("");
        periodEntity.setApplyBusinessState("");
        periodEntity.setSignatureTaskState("");
        periodEntity.setSignatureSusinessState("");
        periodEntity.setStatisticsMonth("");
        periodEntity.setStatisticsTime("");
        periodEntity.setSubmitUserid("");
        periodEntity.setSubmitTime(null);
        periodEntity.setCancelUserid("");
        periodEntity.setCancelTime(null);
        periodEntity.setConfirmUserid("");
        periodEntity.setConfirmTime(null);
        //修改条件
        UpdateWrapper<PeriodEntity> updateWrapper = new UpdateWrapper();
        updateWrapper.eq("tax_number", taxNo);
        periodMapper.update(periodEntity, updateWrapper);
    }
    /**
     * 获取公司税款所属期
     *
     * @param taxNo
     * @return
     */
    private PeriodEntity getTaxNoPeriod(String taxNo) {
        QueryWrapper<PeriodEntity> queryWrapper = new QueryWrapper();
        queryWrapper.eq("tax_number", taxNo);
        return periodMapper.selectOne(queryWrapper);
    }


    /**
     * 对认证发票超过100条要分隔
     *
     * @param auth
     */
    private void splitAuth(InvoiceAuthBodyDTO auth) {
        if (auth.getFpList().size() >= 100) {
            int limit = (auth.getFpList().size() + 100 - 1) / 100;
            List<List<Map<String, String>>> splitlist = new ArrayList<>();
            Stream.iterate(0, n -> n + 1).limit(limit).forEach(i ->
                    splitlist.add(auth.getFpList().stream().skip(i * 100).limit(100).collect(Collectors.toList()))
            );
            InvoiceAuthBodyDTO splitAuthBean = new InvoiceAuthBodyDTO();
            for (List<Map<String, String>> ll : splitlist) {
                splitAuthBean.setUuidList(auth.getUuidList());
                splitAuthBean.setNsrsbh(auth.getNsrsbh());
                splitAuthBean.setPeriod(auth.getPeriod());
                splitAuthBean.setFpList(ll);
                splitAuthBean.setAuthMode(auth.getAuthMode());
                authPost(splitAuthBean);
            }
        } else {
            authPost(auth);
        }
    }


    /**
     * 北京抵账认证
     *
     * @param auth
     */
    private void authPost(InvoiceAuthBodyDTO auth) {
        Response response = null;
        try {
            response = apiClientService.auth(auth);
        } catch (Exception e) {
            log.error("认证异常：", e);
        }
        //判断调用成功
        if (response != null && CodeConstant.T0000.equals(response.getCode())) {
            List<InvoiceAuthRespDTO> authes = JSON.parseArray(response.getData().toString(), InvoiceAuthRespDTO.class);
            updateAuthSuccess(authes,auth.getAuthMode());
        } else if (response != null) {
            updateAuthBatchError(auth, response.getCode(), response.getMsg());
        }
    }

    /**
     * 认证成功修改数据库
     *
     * @param authes
     */
    private void updateAuthSuccess(List<InvoiceAuthRespDTO> authes,String authMode) {
        ElectronicledgerEntity entity;
        UpdateWrapper<ElectronicledgerEntity> updateWrapper;
        for (InvoiceAuthRespDTO dto : authes) {
            entity = new ElectronicledgerEntity();
            String authResult = dto.getDeductibleResult();
            //认证成功修改值
            if (CodeConstant.COMM_CODE_1.equals(authResult) || CodeConstant.COMM_CODE_4.equals(authResult)) {
                if (CodeConstant.QXGX.equals(authMode)){
                    entity.setAuthState(CodeConstant.COMM_CODE_0);
                    entity.setAuthResult(CodeConstant.COMM_CODE_00);
                    entity.setSubmitState(CodeConstant.COMM_CODE_0);
                }else {
                    entity.setAuthState(CodeConstant.COMM_CODE_1);
                    entity.setAuthResult(authResult);
                }
                entity.setAuthPeriod(dto.getDeductiblePeriod());
                entity.setAuthMode(dto.getDeductibleMode());
                entity.setValidTax(new BigDecimal(dto.getValidTax()));
                entity.setManagementState(dto.getManagementStatus());
                entity.setAuthDate(dto.getDeductibleDate());
            } else {
                entity.setAuthState(CodeConstant.COMM_CODE_2);
                entity.setAuthResult(authResult);
            }
            //修改条件
            updateWrapper = new UpdateWrapper();
            updateWrapper.eq("invoice_code", dto.getInvoiceCode());
            updateWrapper.eq("invoice_no", dto.getInvoiceNumber());
            baseMapper.update(entity, updateWrapper);
        }
    }

    /**
     * 发票认证失败批量更新结果
     *
     * @param auth
     * @param code
     */
    private void updateAuthBatchError(InvoiceAuthBodyDTO auth, String code, String content) {
        List<Map<String, String>> fpList = auth.getFpList();
        for (Map<String, String> map : fpList) {
            String invoiceCode = MapUtils.getString(map, "InvoiceCode");
            String invoiceNo = MapUtils.getString(map, "InvoiceNumber");
            QueryWrapper<ElectronicledgerEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("invoice_code",invoiceCode);
            queryWrapper.eq("invoice_no",invoiceNo);
            ElectronicledgerEntity entity = new ElectronicledgerEntity();
            entity.setAuthState(CodeConstant.COMM_CODE_2);
            entity.setAuthResultContent(content);
            entity.setAuthResult(code);
            baseMapper.update(entity,queryWrapper);
        }
    }


}
